<template>
  <el-form :model="model" :rules="rules" class="form" :inline="true" :label-position="labelPosition || 'top'" ref="FormFef">
    <el-form-item :style="formItem.style" :prop="String(key)" :label="formItem.label" v-for="(formItem, key) in formSchema" :key="key">
      <component v-model="formItem.value" :formItem="formItem" :is="getComponent(formItem.type)" @update:modelValue="emits('onChange', formItem)"></component>
    </el-form-item>
  </el-form>
</template>
<script lang="ts">
export default {name: 'Form'};
</script>
<script setup lang="ts">
import {computed, ref} from 'vue';
import {ElForm, FormRules} from 'element-plus';
import {ComponentMap} from './constants';
import {IComponentMapKey, IFormSchema, IFormSchemaType, IFromItem} from './type';
import {cloneDeep} from 'lodash';

const FormFef = ref<InstanceType<typeof ElForm>>();

const props = defineProps<{
  formSchema: IFormSchema;
  labelPosition?: 'top' | 'left' | 'right';
}>();

const emits = defineEmits<{
  (_e: 'onChange', _value: IFromItem): void;
}>();

const model = computed(() =>
  Object.entries(props.formSchema).reduce((prev: Record<string, any>, [key, value]) => {
    prev[key] = value.value;
    return prev;
  }, {})
);

const rules = ref<FormRules>(
  Object.entries(props.formSchema).reduce((prev: FormRules, [key, value]) => {
    prev[key] = value.rules || [{required: true, message: '该项为必填项'}];
    return prev;
  }, {})
);

const getComponent = (type: IFormSchemaType) => {
  return ComponentMap[type as IComponentMapKey] || ComponentMap.Select;
};

const getValue = async () => {
  await FormFef.value?.validate();
  return cloneDeep(model.value);
};

defineExpose({getValue});
</script>

<style lang="scss" scoped>
.form {
  gap: 20px;
}
:deep(.el-form-item) {
  margin: 0;
  width: 220px;
  .el-input,
  .el-select {
    width: 100%;
  }
}
</style>
